home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / unix / src / amigados.c < prev    next >
C/C++ Source or Header  |  1992-09-02  |  7KB  |  300 lines

  1. #include "amiga.h"
  2. #include "files.h"
  3. #include "signals.h"
  4. #include <exec/memory.h>
  5. #include <fcntl.h>
  6. #include <sys/termios.h>
  7. #include <amiga/ioctl.h>
  8. #include <string.h>
  9.  
  10. /* Code for fd's describing AmigaDOS files */
  11.  
  12. struct amigainfo
  13. {
  14.     BPTR fh;
  15.     BPTR lock;            /* A lock on the file (may be null) */
  16.     long protection;        /* To be set when file is closed, -1 for none */
  17.     char interactive;        /* True if file was interactive */
  18.     char deleted;        /* True if file has been deleted but not closed */
  19. };
  20.  
  21. static ULONG file_select_start(void *userinfo, int rd, int wr)
  22. {
  23.   /* Input always immediately available, gniark */
  24.   return (ULONG)-1;
  25. }
  26.  
  27. static void file_select_poll(void *userinfo, int *rd, int *wr)
  28. {
  29.   /* Input always immediately available, gniark */
  30. }
  31.  
  32. static int file_read(void *userinfo, void *buffer, unsigned int length)
  33. {
  34.   struct amigainfo *info = userinfo;
  35.   BPTR fh = info->fh;
  36.   LONG cnt;
  37.  
  38.   if (info->deleted) return 0;
  39.   if ((cnt = Read(fh, buffer, length)) == -1) ERROR;
  40.   return (int)cnt;
  41. }
  42.  
  43. static int file_write(void *userinfo, void *buffer, unsigned int length)
  44. {
  45.   struct amigainfo *info = userinfo;
  46.   BPTR fh = info->fh;
  47.   int cnt;
  48.  
  49.   if (info->deleted) return 0;
  50.   if (info->interactive)
  51.     {
  52.       char *bufend = (char *)buffer + length;
  53.       
  54.       /* Write by lines, more pleasant for user */
  55.       cnt = 0;
  56.       while (length)
  57.     {
  58.       char *end = buffer;
  59.       long nb;
  60.       unsigned len;
  61.  
  62.       while (end < bufend && *end != '\n') end++;
  63.       if (end == bufend) len = end - (char *)buffer;
  64.       else len = end + 1 - (char *)buffer;
  65.  
  66.       if ((nb = Write(fh, buffer, len)) == -1) ERROR;
  67.       cnt += nb;
  68.       if (nb != len) break;
  69.       
  70.       buffer = end + 1;
  71.       length -= nb;
  72.       /* Interrupt write ? */
  73.       if (_handle_signals(_check_signals(0))) break;
  74.     }
  75.     }
  76.   else if ((cnt = Write(fh, buffer, length)) == -1) ERROR;
  77.   return cnt;
  78. }
  79.  
  80. static int file_lseek(void *userinfo, long rpos, int mode)
  81. {
  82.   struct amigainfo *info = userinfo;
  83.   BPTR fh = info->fh;
  84.   LONG pos, err;
  85.  
  86.   if (info->deleted) return 0;
  87.   pos = Seek(fh, rpos, mode - 1);
  88.   err = IoErr();
  89.   if (pos == -1 || err)
  90.     {
  91.       errno = convert_oserr(err);
  92.       return -1;
  93.     }
  94.   pos = Seek(fh, 0, OFFSET_CURRENT);
  95.   if (pos == -1 || err)
  96.     {
  97.       errno = convert_oserr(err);
  98.       return -1;
  99.     }
  100.   return pos;
  101. }
  102.  
  103. static int file_close(void *userinfo, int internal)
  104. {
  105.   struct amigainfo *info = userinfo;
  106.   BPTR fh = info->fh;
  107.   long protection = info->protection;
  108.   char name[256];
  109.   int ok, deleted;
  110.  
  111.   if (info->lock) UnLock(info->lock);
  112.   deleted = info->deleted;
  113.   free(info);
  114.   if (deleted) return 0;
  115.  
  116.   ok = NameFromFH(fh, name, 256);
  117.   if (internal || Close(fh))
  118.     if (!ok || protection == -1 || SetProtection(name, protection)) return 0;
  119.   ERROR;
  120. }
  121.  
  122. static int isfifo(BPTR fh)
  123. /* Requires: IsInteractive(fh) */
  124. /* Try & find out if fh is a fifo: file */
  125. {
  126.     WaitForChar(fh, 0);
  127.  
  128.     return IoErr() == ERROR_ACTION_NOT_KNOWN;
  129. }
  130.  
  131. static int GetWinBounds (BPTR fh, long *width, long *height)
  132. {
  133.   char buffer[16];
  134.   int ok = 0;
  135.  
  136.   if (!isfifo(fh) && SetMode (fh, 1))
  137.     {
  138.       if ((Write (fh, "\x9b" "0 q", 4) == 4) &&
  139.       WaitForChar (fh, 10000L) &&
  140.       (Read (fh, buffer, sizeof (buffer)) > 9) &&
  141.       (buffer[0] == '\x9b'))
  142.     {
  143.       int y = StrToLong (buffer+5, height);
  144.       int x = StrToLong (buffer+5+y+1, width);
  145.       if ((x != -1) && (y != -1)) ok = 1;
  146.     }
  147.       SetMode (fh, 0);
  148.     }
  149.   return ok;
  150. }
  151.  
  152. int _do_truncate(BPTR fh, off_t length)
  153. {
  154.   int err, ret = -1;
  155.   long oldsize, oldpos;
  156.  
  157.   oldpos = Seek(fh, 0, OFFSET_END);
  158.   oldsize = Seek(fh, 0, OFFSET_END);
  159.  
  160.   if (!(err = IoErr()) &&
  161.       SetFileSize(fh, length, OFFSET_BEGINNING) == length)
  162.     {
  163.       if (oldsize < length)
  164.     {
  165.       /* Zero extra bytes */
  166.       off_t bufsize = length - oldsize, left = bufsize;
  167.       char *buf;
  168.       char reserve[512];
  169.  
  170.       if (!(buf = AllocMem(bufsize, MEMF_CLEAR)))
  171.         {
  172.           bufsize = AvailMem(MEMF_LARGEST) / 2;
  173.  
  174.           if (bufsize < 512 || !(buf = AllocMem(bufsize, MEMF_CLEAR)))
  175.         {
  176.           bufsize = 512;
  177.           buf = reserve;
  178.           memset(reserve, 0, 512);
  179.         }
  180.         }
  181.       while (left > 0)
  182.         {
  183.           long count = left > bufsize ? bufsize : left;
  184.  
  185.           chkabort();
  186.           if (Write(fh, buf, count) != count)
  187.         {
  188.           err = IoErr();
  189.           break;
  190.         }
  191.           left -= count;
  192.         }
  193.       if (buf != reserve) FreeMem(buf, bufsize);
  194.     }
  195.       if (!err) ret = 0;
  196.     }
  197.   if (oldpos < length) Seek(fh, oldpos, OFFSET_BEGINNING);
  198.  
  199.   if (ret) errno = convert_oserr(err);
  200.   return ret;
  201. }
  202.  
  203. static int file_ioctl(void *userinfo, int request, void *data)
  204. {
  205.   struct amigainfo *info = userinfo;
  206.   BPTR fh = info->fh;
  207.  
  208.   if (!info->deleted)
  209.     switch (request)
  210.       {
  211.       case TIOCGWINSZ: {
  212.     struct winsize *ws = data;
  213.     long col, row;
  214.  
  215.     if (info->interactive && GetWinBounds(fh, &col, &row)) 
  216.       {
  217.         ws->ws_col = col; ws->ws_row = row;
  218.         return 0;
  219.       }
  220.     errno = ENOTTY;
  221.     return -1;
  222.       }
  223.       case _AMIGA_INTERACTIVE: {
  224.     int *inter = data;
  225.  
  226.     *inter = IsInteractive(fh);
  227.     return 0;
  228.       }
  229.       case _AMIGA_GET_FH: {
  230.     BPTR *gotfh = data;
  231.  
  232.     *gotfh = fh;
  233.     return 0;
  234.       }
  235.       case _AMIGA_FREE_FH: return 0;
  236.       case _AMIGA_TRUNCATE: {
  237.     off_t length = *(off_t *)data;
  238.  
  239.     return _do_truncate(fh, length);
  240.       }
  241.       case _AMIGA_SETPROTECTION:
  242.     info->protection = *(long *)data;
  243.     return 0;
  244.       case _AMIGA_DELETE_IF_ME: {
  245.     BPTR nlock = *(BPTR *)data;
  246.  
  247.     if (!info->lock) info->lock = DupLockFromFH(info->fh);
  248.     if (info->lock && SameLock(nlock, info->lock) == LOCK_SAME)
  249.       {
  250.         char name[256];
  251.  
  252.         if (NameFromFH(fh, name, 256))
  253.           {
  254.         UnLock(nlock);
  255.         UnLock(info->lock);
  256.         Close(fh);
  257.         SetProtection(name, 0);
  258.         info->deleted = TRUE;
  259.         info->lock = info->fh = 0;
  260.         if (DeleteFile(name)) return 0;
  261.           }
  262.       }
  263.     ERROR;
  264.       }
  265.       }
  266.   errno = EINVAL;
  267.   return -1;
  268. }
  269.  
  270. int _alloc_amigafd(BPTR fh, long protection, long flags)
  271. {
  272.   struct amigainfo *new = (struct amigainfo *)malloc(sizeof(struct amigainfo));
  273.   int fd;
  274.  
  275.   if (!new) { errno = ENOMEM; return -1; }
  276.   new->fh = fh;
  277.   new->lock = NULL;
  278.   new->protection = protection;
  279.   new->deleted = FALSE;
  280.   new->interactive = IsInteractive(fh);
  281.  
  282.   fd = _alloc_fd(new, flags,
  283.          file_select_start, file_select_poll, file_read, file_write,
  284.          file_lseek, file_close, file_ioctl);
  285.   if (fd < 0) free(new);
  286.  
  287.   return fd;
  288. }
  289.  
  290. void _init_unixio(BPTR in, int close_in, BPTR out, int close_out,
  291.           BPTR error, int close_error)
  292. {
  293.   if (_alloc_amigafd(in, -1, FI_READ | (close_in ? 0 : O_NO_CLOSE)) == 0 &&
  294.       _alloc_amigafd(out, -1, FI_WRITE | (close_out ? 0 : O_NO_CLOSE)) == 1 &&
  295.       _alloc_amigafd(error, -1, FI_WRITE | (close_error ? 0 : O_NO_CLOSE)) == 2)
  296.       return;
  297.  
  298.   _fail("Failed to initialise I/O");
  299. }
  300.